#!/usr/bin/python
# -*- coding: UTF-8 -*-

from ast import Not
import sys, os
from datetime import datetime
from threading import Thread
import time

from loguru import logger

import pai_acq

from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QMessageBox
sys.path.append(os.getcwd())
from views.widgets import Ui_acquisition_setting

from qt_material import apply_stylesheet

from utils import app_config
from utils import call_acq_control_driver
from utils import serialport_com
from utils import voltageSerialCommand

class AcquisitionSettingForm(QWidget, Ui_acquisition_setting.Ui_AcquisitionSettingForm):
    def __init__(self, parent = None):
        super(AcquisitionSettingForm, self).__init__(parent)
        self.setupUi(self)

        self.parentMainWindow = None
        self.LastStepButton.clicked.connect(self.lastStep)
        self.AcquisitionEndButton.clicked.connect(self.endAcquisition)
        self.AcquisitionStartButton.clicked.connect(self.startAcquisition)
        self.SetAcqVoltageButton.clicked.connect(self.setAcqVoltage)
        self.global_cancel_flag = False
        self.acquisition_task = None

        self.progressBar_acq.setMinimum(0)
        self.progressBar_acq.setMaximum(100)

        #获取可用的串口
        self.serialPortCom = serialport_com.SerialPortCom()
        portcom = self.serialPortCom.port_check()
        if len(portcom) > 0:
            for key in portcom.keys():
                self.comboBox_Positive_Voltage_COM.addItem(key)
                self.comboBox_Negative_Voltage_COM.addItem(key)

        logger.debug("create an instance of AcquisitionSettingForm successfully.")

    def setMainWindow(self, MainWindow):
        self.parentMainWindow = MainWindow

    def lastStep(self):
        if self.parentMainWindow is not None:
            self.parentMainWindow.acquisitionLastStep()
        else:
            pass
    
    def startAcquisition(self):

        appConfig = app_config.AppConfig()
        matlabSimModEN = appConfig.getMatlabSimulationMode()
        self.GBL_MatlabSimModEN = float(matlabSimModEN)

        self.GBL_FolderPath = appConfig.getACQCmdScriptFolder()
        if not os.path.exists(self.GBL_FolderPath):
            logger.warning("{0} does not exist!", self.GBL_FolderPath)
            return
        
        # #self.comboBox_ExtTrigger.
        # if self.comboBox_ExtTrigger.currentText() == "外部触发":
        #     self.EXTTriggerSelect = float(1)
        # elif self.comboBox_ExtTrigger.currentText() == "内部触发":
        #     self.EXTTriggerSelect = float(0)
        
        self.EXTTriggerSelect = float(self.lineEdit_EXTTriggerSlect.text())
        #self.UltrasoundBaseFreq = float(self.lineEdit_UltrasoundBaseFreq.text()) * 1e6
        self.ACQ_SamleNum = float(self.lineEdit_ImageDepth.text()) 
        self.TX2RX_DelayUs = float(self.lineEdit_TransducerThick.text()) 
        self.ExtTrigNumber = float(self.lineEdit_TriggerNumber.text())
        self.ExtTriggerPeriod = float(self.lineEdit_TriggerPeriod.text()) * 1e-3
        #self.FrameNumber = float(self.lineEdit_FrameNumber.text())
        self.TriggerDelay = float(self.lineEdit_TriggerDelay.text()) 
        self.LineNumber = float(self.lineEdit_LineNumber.text())
        #self.HighVoltageSelect = self.lineEdit_HighVoltageSelect.text()
        pulseCounter = round(float(self.lineEdit_PulseWideCounter.text()) / 5 - 1)
        self.PulseWideCounter = float(pulseCounter if pulseCounter > 0 else 0)
        self.PulsePattern_Code = self.lineEdit_PulsePattern.text()
        #self.PulsePattern_EOP = self.lineEdit_PulsePattern_EOP.text()
        self.PatternRptCycleNum  = float(self.lineEdit_PatternRptCycleNum.text())
        #self.EOP_RptCycleNum = float(self.lineEdit_EOPRptCycleNum.text())
        #self.EOP_PulseWidth = float(self.lineEdit_EOPPulseWidth.text())
        #self.LaserTX_PulseWidth = float(self.lineEdit_LaserTX_PulseWidth.text())
        #self.ACQ_DelayCnt = float(self.lineEdit_ACQ_DelayCnt.text())
        #self.ACQ_PGA = float(self.lineEdit_ACQ_PGA.text())
        #self.ACQ_Attenuation = float(self.lineEdit_ACQ_Attenuation.text())
        self.ACQ_LNA_US = float(self.comboBox_ACQ_LNA_US.currentText())
        self.ACQ_PGA_US = float(self.comboBox_ACQ_PGA_US.currentText())
        self.ACQ_Attenuation_US = float(self.comboBox_ACQ_Attenuation_US.currentText())

        self.ACQ_LNA_PA = float(self.comboBox_ACQ_LNA_PA.currentText())
        self.ACQ_PGA_PA = float(self.comboBox_ACQ_PGA_PA.currentText())
        self.ACQ_Attenuation_PA = float(self.comboBox_ACQ_Attenuation_PA.currentText())        

        paiacq = pai_acq.initialize()
        paiacq.fun_GenUltrasoundCmdScript(
            self.GBL_FolderPath,       # ACQCmdScriptFolder
            self.GBL_MatlabSimModEN,   # Matlab Simulation Mode
            self.EXTTriggerSelect, # external Trigger select 
            self.ACQ_SamleNum ,        # image depth 80mm
            self.TX2RX_DelayUs ,   # Transducer Thick, 1mm
            self.ExtTrigNumber ,      #100-External Trigger, 1-Minitus, ACQ = 4 * 48 = 192 Second, 3Minuts
            self.ExtTriggerPeriod ,  #100ms
            self.TriggerDelay ,      #Trigger in term of us
            self.LineNumber ,        #Constant
            self.PulseWideCounter,   # Number of Pulse in 5ns, example: 1, 5ns Pulse, DivPeriod = 2 * 1
            self.PulsePattern_Code,
            self.PatternRptCycleNum,
            self.ACQ_LNA_PA,
            self.ACQ_PGA_PA,
            self.ACQ_Attenuation_PA,
            self.ACQ_LNA_US,
            self.ACQ_PGA_US,
            self.ACQ_Attenuation_US)


        self.callAcqDriver = call_acq_control_driver.CallAcqDriverControl()
        driverControlExePath = appConfig.getDriverControlExePath()
        acqCmdScriptPath = self.GBL_FolderPath + "REG_CMD_Line_Config.vh"

        acqDataFolder = appConfig.getAcquisitionDataFolder()
        timeNow = datetime.now()
        timefolder = timeNow.strftime("%Y-%m-%d-%H-%M-%S")
        acqDataFolder = acqDataFolder + timefolder
        os.makedirs(acqDataFolder, exist_ok = True)

        self.callAcqDriver.processOneAcq(driverControlExePath, acqCmdScriptPath, acqDataFolder)

        # 后续添加进度条显示采集过程
        totalFileCount = self.ExtTrigNumber
        self.global_cancel_flag = False  #每次采集开始前重置flag, 重置进度条
        self.progressBar_acq.reset()  
        self.acquisition_task = Thread(target = self.__waitForAcquisition, args=[acqDataFolder, totalFileCount])
        self.acquisition_task.start()
        #self.acquisition_task.join()

        #logger.debug("AcquisitionSettingForm.startAcquisition ends successfully.")
    

    def __waitForAcquisition(self, acqDataFolder, totalFileCount):
        try:
            while not self.global_cancel_flag:
                time.sleep(0.01)
                fileNumber = sum([os.path.isfile(os.path.join(acqDataFolder, listx)) for listx in os.listdir(acqDataFolder)])
                if fileNumber < totalFileCount:
                    #进度条显示采集进度
                    display_progress = int((float)(fileNumber)/totalFileCount * 100)
                    self.progressBar_acq.setValue(display_progress)
                    continue
                else:
                    display_progress = 100
                    self.progressBar_acq.setValue(display_progress)
                    break
                
            #self.callAcqDriver.endAcq()
        except Exception as error:
            logger.error(error)
        finally:    
            self.callAcqDriver.endAcq()

    def endAcquisition(self):

        if self.acquisition_task is not None:
            self.global_cancel_flag = True
            self.acquisition_task.join()
            self.progressBar_acq.reset()
        
        if self.parentMainWindow is not None:
            QMessageBox.information(self, "提示", "需要依次关闭激光器模块Q-Switch和Flash控制", QMessageBox.Yes|QMessageBox.No, QMessageBox.Yes)
            #self.parentMainWindow.acquisitionEnd()
            self.parentMainWindow.opoControlLastStep()
        else:
            pass
        logger.debug("AcquisitionSettingForm.endAcquisition ends successfully.")
    
    ## TBD:确认下面的参数（baudrate， bytesize， stopbits， parity）设置是否准确
    def __openSerial(self, com_name):
        portname = com_name
        baudrate = 9600
        bytesize = 8
        stopbits = 1
        parity = "N"
        if not self.serialPortCom.port_open(portname, baudrate, bytesize, stopbits, parity):
            logger.error("Port Error: 此设备串口不能被打开！")
            QMessageBox.critical(self, "Port Error", "此串口不能被打开！")
            return
    
    def setAcqVoltage(self):
        # open positive com
        positiveCom = self.comboBox_Positive_Voltage_COM.currentText()
        self.__openSerial(positiveCom)
        # send data
        mode = "HEX"

        vo = float(self.lineEdit_Voltage.text())   #  v
        vset = int((5 - (vo + 1.5) / 4.8) * 1000)       # mv
        vset = vset if vset < 5000 else 5000
        vset = vset if vset > 0 else 0

        voltage = int(vset)
        sendVoltageData = voltageSerialCommand.fun_Send_VoltageControl(voltage)
        send_com_data = " ".join(sendVoltageData)
        self.serialPortCom.data_send(mode, send_com_data)
        # close positive com
        self.serialPortCom.port_close()
        
        # open negative com
        negativeCom = self.comboBox_Negative_Voltage_COM.currentText()
        self.__openSerial(negativeCom)
        # send data
        sendVoltageData = voltageSerialCommand.fun_Send_VoltageControl(voltage)
        end_com_data = " ".join(sendVoltageData)
        self.serialPortCom.data_send(mode, end_com_data)
        # close negative com
        self.serialPortCom.port_close()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    PAWin = AcquisitionSettingForm()
    apply_stylesheet(app, theme = "dark_teal.xml")
    PAWin.show()
    sys.exit(app.exec_())